package unimelb.discussiontracker.twitter.data.dao.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Repository;

import unimelb.discussiontracker.twitter.common.QueryControl;
import unimelb.discussiontracker.twitter.data.dao.ITweetRankingDao;
import unimelb.discussiontracker.twitter.data.entity.RankType;
import unimelb.discussiontracker.twitter.data.entity.TweetRanking;

@Repository
public class TweetRankingDao extends GenericDataAccessObject<TweetRanking> implements ITweetRankingDao {

    @Override
    public TweetRanking findRankingsByTweetTopicAndIntervalId(long tweetId, long topicId, long intervalId, RankType rankType) {
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("tweetId", tweetId);
        params.put("rankType", rankType);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runSingleResultNamedQuery("TweetRanking.FindByTweetTopicAndIntervalId", params, null);
    }

    @Override
    public long countKeywordBasedRankings(long topicId, long intervalId) {
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("rankType", RankType.Keyword);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runCountQuery("TweetRanking.CountTopRankings", params, null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<TweetRanking> findKeywordBasedRankings(long topicId, long intervalId, QueryControl queryControl) {
        String query = "SELECT ranking FROM TweetRanking ranking JOIN ranking.tweet tweet JOIN tweet.owner WHERE ranking.type = :rankType AND ranking.topic.id = :topicId AND ranking.interval.id = :intervalId";
        query = appendOrderPart(query, queryControl.getSortBy(), queryControl.getSortOrder());

        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("rankType", RankType.Keyword);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runDynamicQuery(query, params, queryControl);
    }

    @Override
    public long countRankingsForUser(long userId, long topicId, long intervalId) {
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("userId", userId);
        params.put("rankType", RankType.User);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runCountQuery("TweetRanking.CountRankingsForUser", params, null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<TweetRanking> findRankingsForUser(long userId, long topicId, long intervalId, QueryControl queryControl) {
        String query = "SELECT ranking FROM TweetRanking ranking JOIN ranking.tweet tweet JOIN tweet.owner user WHERE ranking.type = :rankType AND ranking.topic.id = :topicId AND ranking.interval.id = :intervalId AND user.id = :userId";
        query = appendOrderPart(query, queryControl.getSortBy(), queryControl.getSortOrder());

        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("userId", userId);
        params.put("rankType", RankType.User);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runDynamicQuery(query, params, queryControl);
    }

    @Override
    public long countRankingsForTag(long tagId, long topicId, long intervalId) {
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("tagId", tagId);
        params.put("rankType", RankType.HashTag);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runCountQuery("TweetRanking.CountRankingsForTag", params, null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<TweetRanking> findRankingsForTag(long tagId, long topicId, long intervalId, QueryControl queryControl) {
        String query = "SELECT ranking FROM TweetRanking ranking JOIN ranking.tweet tweet JOIN tweet.hashTags tagAssoc WHERE ranking.type = :rankType AND ranking.topic.id = :topicId AND ranking.interval.id = :intervalId AND tagAssoc.hashTag.id = :tagId";
        query = appendOrderPart(query, queryControl.getSortBy(), queryControl.getSortOrder());

        final Map<String, Object> params = new HashMap<String, Object>();
        params.put("tagId", tagId);
        params.put("rankType", RankType.HashTag);
        params.put("topicId", topicId);
        params.put("intervalId", intervalId);
        return this.runDynamicQuery(query, params, null);
    }

    private String appendOrderPart(String query, String sortBy, String sortOrder) {
        if ("text".equalsIgnoreCase(sortBy)) {
            return query + " ORDER BY ranking.tweet." + sortBy + " " + sortOrder;
        } else {
            return query + " ORDER BY ranking." + sortBy + " " + sortOrder;
        }
    }
}
